﻿// Copyright © Tamir Khason. 
// This source has no relation to the Microsoft Source License for Silverlight Controls (March 2008 Release).
// It uses only ideas, learned from MSDN and not based on Silverlight Controls source code.
// Please see http://blogs.microsoft.co.il/blogs/tamir or http://sharpsoft.net/ for details.
// All other rights reserved. 

using System;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Controls;

namespace Sharpsoft.Controls
{
    [TemplatePart(Name = RangeSlider.ElementRootName, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = RangeSlider.ElementHorizontalTemplateName, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = RangeSlider.ElementHorizontalLowThumbName, Type = typeof(Thumb))]
    [TemplatePart(Name = RangeSlider.ElementHorizontalHighThumbName, Type = typeof(Thumb))]
    [TemplatePart(Name = RangeSlider.ElementHorizontalHighFillerName, Type = typeof(Rectangle))]
    [TemplatePart(Name = RangeSlider.ElementHorizontalLowFillerName, Type = typeof(Rectangle))]
    [TemplatePart(Name = RangeSlider.ElementHorizontalCenterFillerName, Type = typeof(Rectangle))]
    [TemplatePart(Name = RangeSlider.ElementVerticalTemplateName, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = RangeSlider.ElementVerticalLowThumbName, Type = typeof(Thumb))]
    [TemplatePart(Name = RangeSlider.ElementVerticalHighThumbName, Type = typeof(Thumb))]
    [TemplatePart(Name = RangeSlider.ElementVerticalHighFillerName, Type = typeof(Rectangle))]
    [TemplatePart(Name = RangeSlider.ElementVerticalLowFillerName, Type = typeof(Rectangle))]
    [TemplatePart(Name = RangeSlider.ElementVerticalCenterFillerName, Type = typeof(Rectangle))]
    [TemplatePart(Name = RangeSlider.ElementFocusVisualName, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = RangeSlider.StateNormalName, Type = typeof(Storyboard))]
    [TemplatePart(Name = RangeSlider.StateMouseOverName, Type = typeof(Storyboard))]
    [TemplatePart(Name = RangeSlider.StateDisabledName, Type = typeof(Storyboard))]
    public class RangeSlider : DoubleRangeBase
    {
        #region ctor

        public RangeSlider()
        {
            Minimum = 0;
            Maximum = 100;
            ValueHigh = 80;
            ValueLow = 20;
            DisplayStringFormat = "";

            IsTabStop = true;
            IsEnabled = true;
            Orientation = System.Windows.Controls.Orientation.Horizontal;
            GotFocus += delegate { IsFocused = true; };
            LostFocus += delegate { IsFocused = false; };
            KeyDown += delegate(object sender, KeyEventArgs e) { OnKeyPressed(e); };
            MouseEnter += delegate(object sender, MouseEventArgs e) { OnMouseEnter(e); };
            MouseLeave += delegate(object sender, MouseEventArgs e) { OnMouseLeave(e); };
            MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e) { OnMouseLeftButtonDown(e); };
            MouseLeftButtonUp += delegate(object sender, MouseButtonEventArgs e) { OnMouseLeftButtonUp(e); };
            SizeChanged += delegate { UpdateTrackLayout(); };

            //ugly
            ValueHighString = ValueHigh.ToString(DisplayStringFormat);
            ValueLowString = ValueLow.ToString(DisplayStringFormat);

        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            ElementRoot = GetTemplateChild(ElementRootName) as FrameworkElement;
            ElementHorizontalTemplate = GetTemplateChild(ElementHorizontalTemplateName) as FrameworkElement;
            ElementHorizontalLowThumb = GetTemplateChild(ElementHorizontalLowThumbName) as Thumb;
            ElementHorizontalHighThumb = GetTemplateChild(ElementHorizontalHighThumbName) as Thumb;
            ElementVerticalTemplate = GetTemplateChild(ElementVerticalTemplateName) as FrameworkElement;
            ElementVerticalLowThumb = GetTemplateChild(ElementVerticalLowThumbName) as Thumb;
            ElementVerticalHighThumb = GetTemplateChild(ElementVerticalHighThumbName) as Thumb;
            ElementFocusVisual = GetTemplateChild(ElementFocusVisualName) as FrameworkElement;
            ElementHorizontalHighFiller = GetTemplateChild(ElementHorizontalHighFillerName) as Rectangle;
            ElementHorizontalLowFiller = GetTemplateChild(ElementHorizontalLowFillerName) as Rectangle;
            ElementHorizontalCenterFiller = GetTemplateChild(ElementHorizontalCenterFillerName) as Rectangle;
            ElementVerticalHighFiller = GetTemplateChild(ElementVerticalHighFillerName) as Rectangle;
            ElementVerticalLowFiller = GetTemplateChild(ElementVerticalLowFillerName) as Rectangle;
            ElementVerticalCenterFiller = GetTemplateChild(ElementVerticalCenterFillerName) as Rectangle;


            if (ElementRoot != null)
            {
                StateNormal = ElementRoot.Resources[StateNormalName] as Storyboard;
                StateMouseOver = ElementRoot.Resources[StateMouseOverName] as Storyboard;
                StateDisabled = ElementRoot.Resources[StateDisabledName] as Storyboard;
            }
            if (ElementHorizontalLowThumb != null)
            {
                ElementHorizontalLowThumb.DragStarted += delegate(object sender, DragStartedEventArgs e) { OnLowThumbDragStarted(e); };
                ElementHorizontalLowThumb.DragDelta += delegate(object sender, DragDeltaEventArgs e) { OnLowThumbDragDelta(e); };
            }
            if (ElementHorizontalHighThumb != null)
            {
                ElementHorizontalHighThumb.DragStarted += delegate(object sender, DragStartedEventArgs e) { OnHighThumbDragStarted(e); };
                ElementHorizontalHighThumb.DragDelta += delegate(object sender, DragDeltaEventArgs e) { OnHighThumbDragDelta(e); };
            }
            if (ElementVerticalLowThumb != null)
            {
                ElementVerticalLowThumb.DragStarted += delegate(object sender, DragStartedEventArgs e) { OnLowThumbDragStarted(e); };
                ElementVerticalLowThumb.DragDelta += delegate(object sender, DragDeltaEventArgs e) { OnLowThumbDragDelta(e); };
            }
            if (ElementVerticalHighThumb != null)
            {
                ElementVerticalHighThumb.DragStarted += delegate(object sender, DragStartedEventArgs e) { OnHighThumbDragStarted(e); };
                ElementVerticalHighThumb.DragDelta += delegate(object sender, DragDeltaEventArgs e) { OnHighThumbDragDelta(e); };
            }

            if (ThumbLowStyle == default(Style)) ThumbLowStyle = ThumbStyle;
            if (ThumbHighStyle == default(Style)) ThumbHighStyle = ThumbStyle;
            OnIsEnabledChanged(IsEnabled);
            OnOrientationChanged();
            UpdateVisualState();

        }
        #endregion

        #region Orientation

        /// <summary> 
        /// Gets or sets the Orientation possible Value of the Orientation object.
        /// </summary> 
        public System.Windows.Controls.Orientation Orientation
        {
            get { return (System.Windows.Controls.Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        /// <summary> 
        /// Identifies the Orientation dependency property.
        /// </summary> 
        public static readonly DependencyProperty OrientationProperty =
                    DependencyProperty.Register(
                          "Orientation",
                          typeof(Orientation),
                          typeof(RangeSlider),
                          new PropertyMetadata(OnOrientationPropertyChanged));

        /// <summary>
        /// OrientationProperty property changed handler. 
        /// </summary>
        /// <param name="d">LowHighRangeSlider that changed its Orientation.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param> 
        private static void OnOrientationPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            RangeSlider _LowHighRangeSlider = d as RangeSlider;
            if (_LowHighRangeSlider != null && _LowHighRangeSlider.ElementRoot != null)
            {
                _LowHighRangeSlider.OnOrientationChanged();
            }
        }
        #endregion

        #region IsFocused

        /// <summary> 
        /// Gets or sets the IsFocused possible Value of the bool object.
        /// </summary> 
        public bool IsFocused
        {
            get { return (bool)GetValue(IsFocusedProperty); }
            set { SetValue(IsFocusedProperty, value); }
        }

        /// <summary> 
        /// Identifies the IsFocused dependency property.
        /// </summary> 
        public static readonly DependencyProperty IsFocusedProperty =
                    DependencyProperty.Register(
                          "IsFocused",
                          typeof(bool),
                          typeof(RangeSlider),
                          new PropertyMetadata(OnIsFocusedPropertyChanged));

        /// <summary>
        /// IsFocusedProperty property changed handler. 
        /// </summary>
        /// <param name="d">LowHighRangeSlider that changed its IsFocused.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param> 
        private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            RangeSlider _LowHighRangeSlider = d as RangeSlider;
            if (_LowHighRangeSlider != null && _LowHighRangeSlider.ElementRoot != null)
            {
                _LowHighRangeSlider.OnIsFocusChanged(e);
            }
        }

        protected virtual void OnIsFocusChanged(DependencyPropertyChangedEventArgs e)
        {
            UpdateVisualState();
        }
        #endregion

        #region IsDirectionReversed

        /// <summary> 
        /// Gets or sets the IsDirectionReversed possible Value of the bool object.
        /// </summary> 
        public bool IsDirectionReversed
        {
            get { return (bool)GetValue(IsDirectionReversedProperty); }
            set { SetValue(IsDirectionReversedProperty, value); }
        }

        /// <summary> 
        /// Identifies the IsDirectionReversed dependency property.
        /// </summary> 
        public static readonly DependencyProperty IsDirectionReversedProperty =
                    DependencyProperty.Register(
                          "IsDirectionReversed",
                          typeof(bool),
                          typeof(RangeSlider),
                          new PropertyMetadata(OnIsDirectionReversedPropertyChanged));

        /// <summary>
        /// IsDirectionReversedProperty property changed handler. 
        /// </summary>
        /// <param name="d">LowHighRangeSlider that changed its IsDirectionReversed.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param> 
        private static void OnIsDirectionReversedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            RangeSlider _LowHighRangeSlider = d as RangeSlider;
            if (_LowHighRangeSlider != null && _LowHighRangeSlider.ElementRoot != null)
            {
                _LowHighRangeSlider.UpdateTrackLayout();
            }
        }
        #endregion IsDirectionReversed

        #region IsEnabled

        /// <summary> 
        /// Gets or sets the IsEnabled possible Value of the bool object.
        /// </summary> 
        public bool IsEnabled
        {
            get { return (bool)GetValue(IsEnabledProperty); }
            set { SetValue(IsEnabledProperty, value); }
        }

        /// <summary> 
        /// Identifies the IsEnabled dependency property.
        /// </summary> 
        public static readonly DependencyProperty IsEnabledProperty =
                    DependencyProperty.Register(
                          "IsEnabled",
                          typeof(bool),
                          typeof(RangeSlider),
                          new PropertyMetadata(OnIsEnabledPropertyChanged));

        /// <summary>
        /// IsEnabledProperty property changed handler. 
        /// </summary>
        /// <param name="d">LowHighRangeSlider that changed its IsEnabled.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param> 
        private static void OnIsEnabledPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            RangeSlider _LowHighRangeSlider = d as RangeSlider;
            if (_LowHighRangeSlider != null)
            {
                bool value = (bool)e.NewValue;
                _LowHighRangeSlider.OnIsEnabledChanged(value);
            }
        }

        /// <summary> 
        /// Called when the IsEnabled property changes.
        /// </summary>
        /// <param name="isEnabled">New value of the IsEnabled property.</param> 
        protected virtual void OnIsEnabledChanged(bool isEnabled)
        {
            if (ElementHorizontalLowThumb != null)
            {
                ElementHorizontalLowThumb.IsEnabled = isEnabled;
            }
            if (ElementHorizontalHighThumb != null)
            {
                ElementHorizontalHighThumb.IsEnabled = isEnabled;
            }
            if (ElementVerticalLowThumb != null)
            {
                ElementVerticalLowThumb.IsEnabled = isEnabled;
            }
            if (ElementVerticalHighThumb != null)
            {
                ElementVerticalHighThumb.IsEnabled = isEnabled;
            }

            UpdateVisualState();

            if (isEnabled)
            {
                IsTabStop = true;
            }
            else
            {
                IsTabStop = false;
            }
        }
        #endregion IsEnabled

        #region SelectionBrush

        /// <summary> 
        /// Gets or sets the SelectionBrush possible Value of the Brush object.
        /// </summary> 
        public Brush SelectionBrush
        {
            get { return (Brush)GetValue(SelectionBrushProperty); }
            set { SetValue(SelectionBrushProperty, value); }
        }

        /// <summary> 
        /// Identifies the SelectionBrush dependency property.
        /// </summary> 
        public static readonly DependencyProperty SelectionBrushProperty =
                    DependencyProperty.Register(
                          "SelectionBrush",
                          typeof(Brush),
                          typeof(RangeSlider),
                          null);


        #endregion SelectionBrush

        #region BackBrush

        /// <summary> 
        /// Gets or sets the BackBrush possible Value of the Brush object.
        /// </summary> 
        public Brush BackBrush
        {
            get { return (Brush)GetValue(BackBrushProperty); }
            set { SetValue(BackBrushProperty, value); }
        }

        /// <summary> 
        /// Identifies the BackBrush dependency property.
        /// </summary> 
        public static readonly DependencyProperty BackBrushProperty =
                    DependencyProperty.Register(
                          "BackBrush",
                          typeof(Brush),
                          typeof(RangeSlider),
                          null);


        #endregion BackBrush

        #region ThumbStyle

        /// <summary> 
        /// Gets or sets the ThumbStyle possible Value of the Style object.
        /// </summary> 
        public Style ThumbStyle
        {
            get { return (Style)GetValue(ThumbStyleProperty); }
            set { SetValue(ThumbStyleProperty, value); }
        }

        /// <summary> 
        /// Identifies the ThumbStyle dependency property.
        /// </summary> 
        public static readonly DependencyProperty ThumbStyleProperty =
                    DependencyProperty.Register(
                          "ThumbStyle",
                          typeof(Style),
                          typeof(RangeSlider),
                          null);


        #endregion ThumbStyle

        #region ThumbLowStyle

        /// <summary> 
        /// Gets or sets the ThumbLowStyle possible Value of the Style object.
        /// </summary> 
        public Style ThumbLowStyle
        {
            get { return (Style)GetValue(ThumbLowStyleProperty); }
            set { SetValue(ThumbLowStyleProperty, value); }
        }

        /// <summary> 
        /// Identifies the ThumbLowStyle dependency property.
        /// </summary> 
        public static readonly DependencyProperty ThumbLowStyleProperty =
                    DependencyProperty.Register(
                          "ThumbLowStyle",
                          typeof(Style),
                          typeof(RangeSlider),
                          null);
        #endregion ThumbLowStyle

        #region ThumbHighStyle

        /// <summary> 
        /// Gets or sets the ThumbHighStyle possible Value of the Style object.
        /// </summary> 
        public Style ThumbHighStyle
        {
            get { return (Style)GetValue(ThumbHighStyleProperty); }
            set { SetValue(ThumbHighStyleProperty, value); }
        }

        /// <summary> 
        /// Identifies the ThumbHighStyle dependency property.
        /// </summary> 
        public static readonly DependencyProperty ThumbHighStyleProperty =
                    DependencyProperty.Register(
                          "ThumbHighStyle",
                          typeof(Style),
                          typeof(RangeSlider),
                          null);
        #endregion ThumbHighStyle

        //ugly workaround for TemplateBinding
        #region ValueLowString

        /// <summary> 
        /// Gets or sets the ValueLowString possible Value of the string object.
        /// </summary> 
        public string ValueLowString
        {
            get { return (string)GetValue(ValueLowStringProperty); }
            set { SetValue(ValueLowStringProperty, value); }
        }

        /// <summary> 
        /// Identifies the ValueLowString dependency property.
        /// </summary> 
        public static readonly DependencyProperty ValueLowStringProperty =
                    DependencyProperty.Register(
                          "ValueLowString",
                          typeof(string),
                          typeof(RangeSlider),
                          null);
        #endregion ValueLowString

        #region ValueHighString

        /// <summary> 
        /// Gets or sets the ValueHighString possible Value of the string object.
        /// </summary> 
        public string ValueHighString
        {
            get { return (string)GetValue(ValueHighStringProperty); }
            set { SetValue(ValueHighStringProperty, value); }
        }

        /// <summary> 
        /// Identifies the ValueHighString dependency property.
        /// </summary> 
        public static readonly DependencyProperty ValueHighStringProperty =
                    DependencyProperty.Register(
                          "ValueHighString",
                          typeof(string),
                          typeof(RangeSlider),
                          null);


        #endregion ValueHighString
        //end of ugly workaround


        #region DisplayStringFormat

        /// <summary> 
        /// Gets or sets the DisplayStringFormat possible Value of the string object.
        /// </summary> 
        public string DisplayStringFormat
        {
            get { return (string)GetValue(DisplayStringFormatProperty); }
            set { SetValue(DisplayStringFormatProperty, value); }
        }

        /// <summary> 
        /// Identifies the DisplayStringFormat dependency property.
        /// </summary> 
        public static readonly DependencyProperty DisplayStringFormatProperty =
                    DependencyProperty.Register(
                          "DisplayStringFormat",
                          typeof(string),
                          typeof(RangeSlider),
                          null);


        #endregion DisplayStringFormat


        #region on...Changed overrides
        protected override void OnValueHighChanged(double oldValue, double newValue)
        {
            base.OnValueHighChanged(oldValue, newValue);
            if (ElementRoot != null)
            {
                UpdateTrackLayout();

                //BUG??? binding does not works!
                ValueHighString = newValue.ToString(DisplayStringFormat);
            }
        }

        protected override void OnValueLowChanged(double oldValue, double newValue)
        {
            base.OnValueLowChanged(oldValue, newValue);
            if (ElementRoot != null)
            {
                UpdateTrackLayout();

                //BUG??? binding does not works!
                ValueLowString = newValue.ToString(DisplayStringFormat);
            }
        }

        protected override void OnMaximumChanged(double oldMaximum, double newMaximum)
        {
            base.OnMaximumChanged(oldMaximum, newMaximum);
            if (ElementRoot != null)
            {
                UpdateTrackLayout();
            }
        }

        protected override void OnMinimumChanged(double oldMinimum, double newMinimum)
        {
            base.OnMinimumChanged(oldMinimum, newMinimum);
            if (ElementRoot != null)
            {
                UpdateTrackLayout();
            }
        }
        #endregion

        #region Mouse events
        private void OnMouseEnter(MouseEventArgs e)
        {
            e.Handled = true;
            IsMouseOver = true;
            if ((Orientation == Orientation.Horizontal && ElementHorizontalLowThumb != null && !ElementHorizontalLowThumb.IsDragging && ElementHorizontalHighThumb != null && !ElementHorizontalHighThumb.IsDragging) ||
                (Orientation == Orientation.Vertical && ElementVerticalLowThumb != null && !ElementVerticalLowThumb.IsDragging && ElementVerticalHighThumb != null && !ElementVerticalHighThumb.IsDragging))
            {
                UpdateVisualState();
            }
        }
        private void OnMouseLeave(MouseEventArgs e)
        {
            e.Handled = true;
            IsMouseOver = false;
            if ((Orientation == Orientation.Horizontal && ElementHorizontalLowThumb != null && !ElementHorizontalLowThumb.IsDragging && ElementHorizontalHighThumb != null && !ElementHorizontalHighThumb.IsDragging) ||
                (Orientation == Orientation.Vertical && ElementVerticalLowThumb != null && !ElementVerticalLowThumb.IsDragging && ElementVerticalHighThumb != null && !ElementVerticalHighThumb.IsDragging))
            {
                UpdateVisualState();
            }
        }
        private void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            e.Handled = true;
            Focus();
            CaptureMouse();
        }
        private void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            e.Handled = true;
            ReleaseMouseCapture();
            UpdateVisualState();
        }
        #endregion

        #region Key events
        private void OnKeyPressed(KeyEventArgs e)
        {
            if (!IsEnabled)
            {
                return;
            }
        }
        #endregion

        #region Changing
        internal void UpdateVisualState()
        {
            if (!IsEnabled)
            {
                ChangeVisualState(StateDisabled ?? StateNormal);
            }
            else
            {
                if (IsMouseOver)
                {
                    ChangeVisualState(StateMouseOver ?? StateNormal);
                }
                else
                {
                    ChangeVisualState(StateNormal);
                }
            }

            if (ElementFocusVisual != null)
            {
                ElementFocusVisual.Visibility = (IsFocused && IsEnabled) ?
                    Visibility.Visible : Visibility.Collapsed;
            }



        }
        internal void ChangeVisualState(Storyboard state)
        {
            Storyboard previousState = _currentState;
            if (state == previousState)
            {
                return;
            }

            if (state != null)
            {
                if (previousState != null)
                {
                    previousState.Stop();
                }
                _currentState = state;
                state.Begin();
            }
        }
        #endregion

        #region ThumbDragDelta
        private void OnLowThumbDragStarted(DragStartedEventArgs e)
        {
            this._dragValue = this.ValueLow;
        }
        private void OnHighThumbDragStarted(DragStartedEventArgs e)
        {
            this._dragValue = this.ValueHigh;
        }
        private void OnLowThumbDragDelta(DragDeltaEventArgs e)
        {
            double offset = 0;

            if (Orientation == Orientation.Horizontal && ElementHorizontalLowThumb != null)
            {
                offset = e.HorizontalChange / (ActualWidth - ElementHorizontalLowThumb.ActualWidth) * (Maximum - Minimum);
            }
            else if (Orientation == Orientation.Vertical && ElementVerticalLowThumb != null)
            {
                offset = -e.VerticalChange / (ActualHeight - ElementVerticalLowThumb.ActualHeight) * (Maximum - Minimum);
            }

            if (!double.IsNaN(offset) && !double.IsInfinity(offset))
            {
                _dragValue += IsDirectionReversed ? -offset : offset;

                double newValue = Math.Min(Maximum, Math.Max(Minimum, _dragValue));

                if (newValue != ValueLow)
                {
                    ValueLow = newValue;
                }
            }
        }
        private void OnHighThumbDragDelta(DragDeltaEventArgs e)
        {
            double offset = 0;

            if (Orientation == Orientation.Horizontal && ElementHorizontalHighThumb != null)
            {
                offset = e.HorizontalChange / (ActualWidth - ElementHorizontalHighThumb.ActualWidth) * (Maximum - Minimum);
            }
            else if (Orientation == Orientation.Vertical && ElementVerticalHighThumb != null)
            {
                offset = -e.VerticalChange / (ActualHeight - ElementVerticalHighThumb.ActualHeight) * (Maximum - Minimum);
            }

            if (!double.IsNaN(offset) && !double.IsInfinity(offset))
            {
                _dragValue += IsDirectionReversed ? -offset : offset;

                double newValue = Math.Min(Maximum, Math.Max(Minimum, _dragValue));

                if (newValue != ValueHigh)
                {
                    ValueHigh = newValue;
                }
            }
        }
        #endregion

        #region UpdateTrackLayout

        /// <summary> 
        /// This code will run whenever Orientation changes, to change the template
        /// being used to display this control. 
        /// </summary>
        protected virtual void OnOrientationChanged()
        {
            if (ElementHorizontalTemplate != null)
            {
                ElementHorizontalTemplate.Visibility = (Orientation == Orientation.Horizontal ? Visibility.Visible : Visibility.Collapsed);
            }
            if (ElementVerticalTemplate != null)
            {
                ElementVerticalTemplate.Visibility = (Orientation == Orientation.Horizontal ? Visibility.Collapsed : Visibility.Visible);
            }
            UpdateTrackLayout();
        }

        /// <summary> 
        /// This method will take the current min, max, and value to 
        /// calculate and layout the current control measurements.
        /// </summary> 
        protected virtual void UpdateTrackLayout()
        {
            double maximum = Maximum;
            double minimum = Minimum;
            double valueLow = ValueLow;
            double valueHigh = ValueHigh;



            Grid templateGrid = (Orientation == Orientation.Horizontal) ? (ElementHorizontalTemplate as Grid) : (ElementVerticalTemplate as Grid);
            if (templateGrid != null)
            {
                if (Orientation == Orientation.Horizontal && templateGrid.ColumnDefinitions != null &&
                    templateGrid.ColumnDefinitions.Count == 5)
                {
                    templateGrid.ColumnDefinitions[0].Width = new GridLength(1, IsDirectionReversed ? GridUnitType.Star : GridUnitType.Auto);
                    templateGrid.ColumnDefinitions[4].Width = new GridLength(1, IsDirectionReversed ? GridUnitType.Auto : GridUnitType.Star);
                }
                else if (Orientation == Orientation.Vertical && templateGrid.RowDefinitions != null &&
                    templateGrid.RowDefinitions.Count == 5)
                {
                    templateGrid.RowDefinitions[0].Height = new GridLength(1, IsDirectionReversed ? GridUnitType.Auto : GridUnitType.Star);
                    templateGrid.RowDefinitions[4].Height = new GridLength(1, IsDirectionReversed ? GridUnitType.Star : GridUnitType.Auto);
                }
            }

            if (Orientation == Orientation.Horizontal && ElementHorizontalCenterFiller != null &&
                ElementHorizontalLowFiller != null && ElementHorizontalLowThumb != null &&
                ElementHorizontalHighFiller != null && ElementHorizontalHighThumb != null)
            {
                ElementHorizontalLowFiller.Width = (valueLow - minimum) * (ActualWidth - ElementHorizontalHighThumb.ActualWidth - ElementHorizontalLowThumb.ActualWidth) / (maximum - minimum);
                ElementHorizontalCenterFiller.Width = (valueHigh - valueLow) * (ActualWidth - ElementHorizontalHighThumb.ActualWidth - ElementHorizontalLowThumb.ActualWidth) / (maximum - minimum);
                ElementHorizontalHighFiller.Width = (maximum - valueHigh) * (ActualWidth - ElementHorizontalHighThumb.ActualWidth - ElementHorizontalLowThumb.ActualWidth) / (maximum - minimum);

            }
            else if (Orientation == Orientation.Vertical && ElementVerticalCenterFiller != null &&
                ElementVerticalLowFiller != null && ElementVerticalLowThumb != null &&
                ElementVerticalHighFiller != null && ElementVerticalHighThumb != null)
            {
                ElementVerticalLowFiller.Height = (valueLow - minimum) * (ActualHeight - ElementVerticalLowThumb.ActualHeight - ElementVerticalHighThumb.ActualHeight) / (maximum - minimum);
                ElementVerticalCenterFiller.Height = (valueHigh - valueLow) * (ActualHeight - ElementVerticalLowThumb.ActualHeight - ElementVerticalHighThumb.ActualHeight) / (maximum - minimum);
                ElementVerticalHighFiller.Height = (maximum - valueHigh) * (ActualHeight - ElementVerticalLowThumb.ActualHeight - ElementVerticalHighThumb.ActualHeight) / (maximum - minimum);
            }
        }

        #endregion

        #region Template Parts
        /// <summary> 
        /// Root of the thumb template.
        /// </summary>
        internal FrameworkElement ElementRoot { get; set; }
        internal const string ElementRootName = "RootElement";

        /// <summary> 
        /// Horizontal template root 
        /// </summary>
        internal virtual FrameworkElement ElementHorizontalTemplate { get; set; }
        internal const string ElementHorizontalTemplateName = "HorizontalTemplateElement";

        /// <summary> 
        /// Thumb for dragging track 
        /// </summary>
        internal virtual Thumb ElementHorizontalLowThumb { get; set; }
        internal const string ElementHorizontalLowThumbName = "HorizontalLowThumbElement";

        /// <summary> 
        /// Thumb for dragging track 
        /// </summary>
        internal virtual Thumb ElementHorizontalHighThumb { get; set; }
        internal const string ElementHorizontalHighThumbName = "HorizontalHighThumbElement";

        /// <summary> 
        /// Horizontal high filler
        /// </summary>
        internal virtual Rectangle ElementHorizontalHighFiller { get; set; }
        internal const string ElementHorizontalHighFillerName = "HorizontalHighFillerElement";

        /// <summary> 
        /// Horizontal center filler
        /// </summary>
        internal virtual Rectangle ElementHorizontalCenterFiller { get; set; }
        internal const string ElementHorizontalCenterFillerName = "HorizontalCenterFillerElement";

        /// <summary> 
        /// Horizontal low filler
        /// </summary>
        internal virtual Rectangle ElementHorizontalLowFiller { get; set; }
        internal const string ElementHorizontalLowFillerName = "HorizontalLowFillerElement";

        /// <summary> 
        /// Vertical template root
        /// </summary>
        internal virtual FrameworkElement ElementVerticalTemplate { get; set; }
        internal const string ElementVerticalTemplateName = "VerticalTemplateElement";

        /// <summary> 
        /// Thumb for dragging track
        /// </summary>
        internal virtual Thumb ElementVerticalLowThumb { get; set; }
        internal const string ElementVerticalLowThumbName = "VerticalLowThumbElement";

        /// <summary> 
        /// Thumb for dragging track
        /// </summary>
        internal virtual Thumb ElementVerticalHighThumb { get; set; }
        internal const string ElementVerticalHighThumbName = "VerticalHighThumbElement";

        /// <summary> 
        /// Vertical high filler
        /// </summary>
        internal virtual Rectangle ElementVerticalHighFiller { get; set; }
        internal const string ElementVerticalHighFillerName = "VerticalHighFillerElement";

        /// <summary> 
        /// Vertical center filler
        /// </summary>
        internal virtual Rectangle ElementVerticalCenterFiller { get; set; }
        internal const string ElementVerticalCenterFillerName = "VerticalCenterFillerElement";

        /// <summary> 
        /// Vertical low filler
        /// </summary>
        internal virtual Rectangle ElementVerticalLowFiller { get; set; }
        internal const string ElementVerticalLowFillerName = "VerticalLowFillerElement";

        /// <summary> 
        /// Focus indicator of the Slider template.
        /// </summary>
        internal FrameworkElement ElementFocusVisual { get; set; }
        internal const string ElementFocusVisualName = "FocusVisualElement";

        /// <summary> 
        /// Transition into the Normal state in the Slider template. 
        /// </summary>
        internal Storyboard StateNormal { get; set; }
        internal const string StateNormalName = "Normal State";

        /// <summary> 
        /// Transition into the MouseOver state in the Slider template.
        /// </summary>
        internal Storyboard StateMouseOver { get; set; }
        internal const string StateMouseOverName = "MouseOver State";

        /// <summary> 
        /// Transition into the Disabled state in the Slider template.
        /// </summary>
        internal Storyboard StateDisabled { get; set; }
        internal const string StateDisabledName = "Disabled State";

        #endregion Template Parts

        #region Members
        /// <summary> 
        /// Whether the mouse is currently over the control
        /// </summary>
        internal bool IsMouseOver { get; set; }

        /// <summary>
        /// Current state of the control 
        /// </summary> 
        internal Storyboard _currentState;

        /// <summary>
        /// Accumulates drag offsets in case the mouse drags off the end of the track.
        /// </summary> 
        private double _dragValue;
        #endregion

    }
}
